Spring RestTempate 打印请求和响应内容日志

您所在的位置:网站首页 JAVA debug打印自定义bean Spring RestTempate 打印请求和响应内容日志

Spring RestTempate 打印请求和响应内容日志

2024-07-14 22:33:52| 来源: 网络整理| 查看: 265

系统中经常需要调用第三方接口实现业务功能,为了方便调试和定位问题,我们通常需要将接口调用参数和返回结果打印到日志文件中。在Spring项目中一般会用RestTemplate来调用第三方接口。 通过在RestTemplate调用过程中统一打印日志,可以保持代码的整洁,也可以统一日志格式,比在业务逻辑中到处打印接口调用日志要方便的多。

具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-rest-template-log

一、概述

RestTemplate使用前需要先定义bean,在定义bean时可以通过指定interceptors来打印日志。

二、定义RestTemplate的bean,并指定interceptors

RestTemplate的bean的定义在RestTemplateConfig类中实现。

RestTemplateConfig.java:

@Bean public RestTemplate restTemplate(RestTemplateBuilder builder) { return builder .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(httpClient())) .interceptors(new CustomClientHttpRequestInterceptor()) .build(); }

其中 interceptors方法用来指定我们自己实现的日志打印 interceptors 。

三、实现日志打印 interceptors

自定义的interceptors需要实现 ClientHttpRequestInterceptor 这个 interface。

static class CustomClientHttpRequestInterceptor implements ClientHttpRequestInterceptor { @Override @NonNull public ClientHttpResponse intercept(HttpRequest request, @NonNull byte[] bytes, @NonNull ClientHttpRequestExecution execution) throws IOException { log.info("HTTP Method: {}, URI: {}, Headers: {}", request.getMethod(), request.getURI(), request.getHeaders()); request.getMethod(); if (request.getMethod().equals(HttpMethod.POST)) { log.info("HTTP body: {}", new String(bytes, StandardCharsets.UTF_8)); } ClientHttpResponse response = execution.execute(request, bytes); ClientHttpResponse responseWrapper = new BufferingClientHttpResponseWrapper(response); String body = StreamUtils.copyToString(responseWrapper.getBody(), StandardCharsets.UTF_8); log.info("RESPONSE body: {}", body); return responseWrapper; } }

接口请求地址和请求参数的日志打印比较简单,将intercept方法中的参与打印到日志中即可。

返回结果的body的日志打印需要做一些特殊处理。

ClientHttpResponse response = execution.execute(request, bytes);这行代码我们拿到了返回结果,但是不能直接读取返回的数据。

因为返回结果中的getBody()方法返回的是 InputStream ,直接读取后,会导致后续的处理拿不到结果。

因此我们需要对返回execution.execute方法返回的结果进行包装,将返回结果放到自定义的BufferingClientHttpResponseWrapper类中。

ClientHttpResponse responseWrapper = new BufferingClientHttpResponseWrapper(response);

BufferingClientHttpResponseWrapper类会将body的数据复制到一个本地变量中,用于支持多次读取。

BufferingClientHttpResponseWrapper类的实现如下:

static class BufferingClientHttpResponseWrapper implements ClientHttpResponse { private final ClientHttpResponse response; private byte[] body; BufferingClientHttpResponseWrapper(ClientHttpResponse response) { this.response = response; } @NonNull public HttpStatusCode getStatusCode() throws IOException { return this.response.getStatusCode(); } @NonNull public int getRawStatusCode() throws IOException { return this.response.getRawStatusCode(); } @NonNull public String getStatusText() throws IOException { return this.response.getStatusText(); } @NonNull public HttpHeaders getHeaders() { return this.response.getHeaders(); } @NonNull public InputStream getBody() throws IOException { if (this.body == null) { this.body = StreamUtils.copyToByteArray(this.response.getBody()); } return new ByteArrayInputStream(this.body); } public void close() { this.response.close(); } }

这个类主要是对 getBody()进行了特殊处理,在方法调用时,通过 treamUtils.copyToByteArray将body数据复制到本地变量中。

每次读取body时,都会从本地变量中读取,避免了第一次读取body后,后续再读取body会读不到数据的问题。

四、调用接口查看日志内容

我们在代码中模拟调用一个第三方接口 http://someservice/foo,接口调用在 DemoController 类中实现:

@GetMapping("/demo/get") public Object demoGet(String arg) { return restTemplate.postForObject("http://someservice/foo", new BodyRequest("test"), BodyRequest.class); }

在单元测试代码 DemoApplicationTest中调用这个接口。

String resp = testRestTemplate.getForObject("/demo/get?arg=test", String.class)

执行单元测试代码后,可以看到日志中打印的接口调用参数和返回结果:

HTTP Method: POST, URI: http://someservice/foo, Headers: [Accept:"application/json, application/*+json", Content-Type:"application/json", Content-Length:"15"] HTTP body: {"arg1":"test"} RESPONSE body: {"code": 200}

日志中打印的返回结果 {"code": 200}是我们在单元测试中对 http://someservice/foo接口mock的数据。

具体如何对第三方接口进行mock,可以参照 springboot单元测试技术 这篇文章。



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭